1.条件语句
if条件语句,如果括号内的运算式结果为true,那么紧接着if之后的那一条语句会被执行。
当if后接多条语句时,则必须在if语句之后以大括号{}
的形式将这些执行语句括起来,成为一个语句块。
1 | if(statement=true) |
常见的错误是多条执行语句时忘记加大括号。例如
1 |
|
另外,当面临两种选择,但是其中的一种选择又嵌套了多种选择的情况下,可以采取如下的处理方式:
1 |
|
2.vector赋初值
1 |
|
3.数组指针与指针数组
部分转自Romi-知行合一 的博客。
对于这两个概念的中文翻译太过于拗口,或许其英文名可能更加直白一些。
指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针。本质是数组,其中的每一个元素都是指针。
数组指针:a pointer to an array,即指向数组的指针。本质是指针,指针指向数组的起始地址。
还要注意的是他们用法的区别,下面举例说明。
int* a[4]
指针数组
表示:数组a中的元素都为int型指针
元素表示:*a[i] *(a[i])是一样的,因为[]优先级高于*
int (*a)[4]
数组指针
表示:指向数组a的指针
元素表示:(*a)[i]
4.指针
有以下的vector对象:
vector<int>fibonacci,lucas,pell,triangular,square,pentagonal;
当需要一个指针,指向“元素类型为int型的”vector时,指针应该是什么样?
一般,指针的形式为:
1 | type_of_object_pointed_to * name_of_pointer_object |
由于要的指针是指向vector
1 | vector<int> *pv=0; |
同时,还可以采取另一种方式访问这些数列
1 | const int seq_cnt = 6; |
5.文件的读写
包含头文件#include<fstream>
5.1 写
定义一个ofstream对象,并将文件名传入:
1 | ofstream outfile("seq_data.txt") |
使用该命令写入文件时,如果不存在该文件,则新建->写入。如果存在该文件,则写入时会丢弃原来的数据。
如果文件已经存在,我们不希望丢弃原有的数据,而是希望将新数据增加到该文件中,那么必须以追加模式(append mode)打开这个文件 。应该提供第二个参数ios_base::app给ofstream对象,命令为ofstream outfile("seq_data.txt",ios_base::app);
文件有可能打开失败。
//如果outfile求值结果为false,表示该文件并未成功打开
1 |
|
1 |
|
5.2 读
1 |
|
6.fibonacci数组
1 |
|
7. pass by value && pass by reference
pass by value(传值):将对象进行拷贝到被调用函数中,当被调用函数中的值发生变化时,仅仅变化的是这份拷贝,调用函数中的实参并未发生变化。
pass by reference(传址):
1>希望得以对传入的对象直接进行修改。
2>降低复制大型对象的额外负担。
例如:
2.2 调用函数 例题分析一节中,display函数采用的是值传递的方式,虽然这样也能达到显示的目的,但是,如果我们采用如下方式传入vector的地址时,速度可能会更快:
1 |
|
另外,如果有必要,我们也可以选择指针传递的方式来进行
1 |
|
7.1 动态内存管理
dynamic extent(动态范围):内存系由程序的空闲空间分配而来,有时也称为堆内存(heap memory)。由程序员管理,分配:new,释放:delete。
例如:
1 |
|
7.2 局部静态对象
在求Fibonacci数组的函数当中,每次调用fibona_seq(int size)
函数时,都会从头开始递归计算。
例如:
1 |
|
基于以上问题,引入局部静态变量的使用。
例如,如下代码:
1 |
|
7.3 设定头文件
头文件中,包含与程序相关的所有函数申明都放在该文件中。
函数的定义只能有一份,倒是可以有许多分声明。不将函数的定义放到头文件,是因为同一个程序的多个代码文件可能都会包含这个头文件。
原因:
首先必须了解编译的过程,编译的第一步是把所有的CPP文件编译成为点O文件,而且每一个点CPP文件都是单独编译的,该点CPP文件中用到的类型必须在它所include 的头文件当中找到,相当于把它所有include的文件中的代码都加到该CPP文件的前面,但是声明的部分将不会出现在编译后的点O文件,相当于每个CPP文件都是单独编译,因此它的ifndef在一个文件里是没有用的,两个CPP文件里如果包含同一个有ifndef的头文件,效果是两个CPP文件都把该头文件加到它的前面,但不会把声明的部分放到点O文件中,而会把头文件中定义的部分都输出到编译后的点O文件当中
因此如果在头文件当中有一个定义,那么如果有两个CPP文件当中include了它,那么将会出现重定义错误,multiple definition of
由于模板不是真实的定义,所以可以放在头文件当中
声明作用只是在链接的时候进行查找,定位,如果出现对一个声明的两个定义,则会出错
但是内联函数的定义必须要放到头文件中
其实原理很简单,就是当用#include 包含一个文件得时候,预处理得时候会直接展开这一个文件,如果文件中放有某个函数的定义,事实上就相当于把该函数定义放在了这个包含这个文件(上面得例子中得print_inline.h)的文件(main.c)中,这样就可以在main中将print_inline函数内联展开
在很多时候,由于某些函数需要经常被调用,为了加快程序的执行速度,经常要用到inline,但是如果inline函数的定义和声明是分开的,而在另外一个文件中需要调用这些inline函数得时候,内联是无法在这些调用函数内展开的(上面得第二个例子),只能调用。这样内联函数在全局范围内就失去了作用。解决的办法就是把内联函数得定义放在头文件中,当其它文件要调用这些内联函数的时候,只要包含这个头文件就可以了
——转自sunshine的博客
8.基于对象的编程风格
8.1 构造函数和析构函数
首先,构造函数constructor不应指定返回类型,亦不用任何返回值。可以被重载
最简单的构造函数是默认构造函数default constructor。不需要任何参数,其包含了两种情况
- 不接受任何参数
1 |
|
- 这种情况更常见,它为每个参数提供了默认值:
1 |
|
8.1.1 构造函数的第二种初始化方法——成员初始化列表
1 |
|
8.1.2 析构函数(destructor)
绝对不会 有返回值,也没有任何参数。
由于参数列表为空,所以绝对不可能被重载。
考虑如下的Matrix class,其constructor使用new表达式从heap中分配double数组所需的空间。
destructor则负责释放这些内存:
1 |
|
8.1.3 成员逐一初始化
1 |
|
class data member会被依次复制。
本例中的_length,_beg_pos,_next
都会依次从tri1复制到tri2,此即成员的逐一初始化操作
这样逐一初始化有一个潜在的问题,如下
1 |
|
这种情况下,可以提供一个copy constructor,其可以改变“成员逐一初始化”的默认行为。我们可以产生一个独立的数组副本,这样便可以使某个对象的析构操作不至于影响到另一个对象
1 |
|
类中的const常量必须在构造函数的初始化列表中初始化,而不能在构造函数的函数体中初始化。
8.2 类的静态成员
部分转自MoreWindows Blog。
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。
eg1:
通过类名调用静态成员函数和静态成员变量:
1 |
|
编译出错:error C2352: ‘Point::init’ : illegal call of non-static member function
结论1:不能通过类名来调用类的非静态成员函数。
eg2:通过类的对象调用静态成员函数和静态成员变量
1 |
|
编译通过
结论2:类的对象可以使用静态成员函数和非静态成员函数。
eg3:在类的静态成员函数中使用类的非静态成员
1 |
|
编译出错:error C2597: illegal reference to data member ‘Point::m_x’ in a static member function
因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。
结论3:静态成员函数中不能引用非静态成员。
eg4:在类的非静态成员函数中使用类的静态成员。
1 |
|
编译通过,理由如上所述。
但是反过来却不行,不能在类的静态成员函数中使用类的非静态成员。
结论5:类的静态成员变量必须先初始化再使用。
结合上面的五个例子,对类的静态成员变量和成员函数作个总结:
一。静态成员函数中不能调用非静态成员。
二。非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
三。静态成员变量使用前必须先初始化,而且只能在类体外进行。(如int MyClass::m_nNumber = 0;),否则会在linker时出错。